﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace 激光测温探头
{
    public partial class PortableTool : Form
    {
        public SerialPort serial1 = new SerialPort();//新建一个串口类
        bool isRUN = false;//串口状况
        bool isOpen = false;//激光打开状况

        public class CustomComparer : System.Collections.IComparer
        {
            public int Compare(object x, object y)//比较两个字符串的长度
            {
                string s1 = (string)x;
                string s2 = (string)y;

                if (s1.Length > s2.Length) return 1;
                if (s1.Length < s2.Length) return -1;
                return s1.CompareTo(s2);
            }
        }
        public void serial1_send_data(byte[] buffer)//串口1的发送数据函数，串口1将分配给激光测距传感器
        {
            if (buffer.Length > 0)
            {
                if (serial1.IsOpen)
                {
                    serial1.Write(buffer, 0, buffer.Length);

                }
            }
        }
        public static bool ReceModbusDataIsTrue(byte[] Receive, int ReceiveNum)//判断微气象仪收到的帧是否为正确的
        {
            byte[] NeedToMakeCRCdata = new byte[ReceiveNum - 2];//C8 03 02 01 56 E5 FA 
            NeedToMakeCRCdata = Receive.Skip(0).Take(ReceiveNum - 2).ToArray();
            byte[] CRCresult = new byte[2];
            CRCresult = CRC16.CRCCalc(NeedToMakeCRCdata);
            if ((CRCresult[0] == Receive[ReceiveNum - 2]) && (CRCresult[1] == Receive[ReceiveNum - 1]))
            {
                return true;
            }
            return false;
        }
        public PortableTool()
        {
            InitializeComponent();
        }

        private void label2_Click(object sender, EventArgs e)
        {

        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (isRUN == false)
            {
                button4.Text = "停止通信";
                isRUN = true;
                try
                {
                    if (comboBox1.Text == "选择串口")
                    {
                    }
                    else
                    {
                        serial1.PortName = comboBox1.Text;
                        serial1.BaudRate = int.Parse("9600");
                        serial1.Parity = Parity.None;
                        serial1.DataBits = int.Parse("8");
                        serial1.StopBits = StopBits.One;
                        serial1.Open();
                    }

                }
                catch (Exception ex)
                {
                }
            }
            else
            {
                button4.Text = "开始通信";
                isRUN = false;
                serial1.Close();
            }

        }

        private void comboBox1_DropDown(object sender, EventArgs e)
        {
            string port_name_old = comboBox1.Text;

            string[] port_names = SerialPort.GetPortNames();
            Array.Sort(port_names, new CustomComparer());
            comboBox1.Items.Clear();
            comboBox1.Items.AddRange(port_names);
            comboBox1.Items.Add("不选");


            if ((comboBox1.Items.Count > 0) && (comboBox1.SelectedIndex < 0))
            {
                comboBox1.SelectedIndex = 0;
            }
            comboBox1.Text = port_name_old;
        }

        private void button3_Click(object sender, EventArgs e)
        {

            if (isOpen == false)
            {
                button3.Text = "关闭激光"; isOpen = true;
                byte[] MakeLaserOpen = new byte[] { 0x01, 0x0f, 0x00, 0x00, 0x31, 0xDB };
                if (serial1.IsOpen)
                {
                    MakeLaserOpen[0] = BitConverter.GetBytes(int.Parse(textBox1.Text))[0];
                    byte[] NeedToMakeCRCdata = new byte[4];
                    NeedToMakeCRCdata = MakeLaserOpen.Skip(0).Take(4).ToArray();
                    byte[] CRCresult = new byte[2];
                    CRCresult = CRC16.CRCCalc(NeedToMakeCRCdata);
                    MakeLaserOpen[4] = CRCresult[0];
                    MakeLaserOpen[5] = CRCresult[1];
                    serial1_send_data(MakeLaserOpen);
                    System.Threading.Thread.Sleep(500);
                    int bytes = serial1.BytesToRead;

                    byte[] Recbuffer = new byte[7] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 声明一个临时数组存储当前来的串口数据
                    if (bytes == 7)
                    {
                        try { serial1.Read(Recbuffer, 0, 7); } catch { };
                    }
                    else
                    {
                        int bytes_1 = serial1.BytesToRead;
                        byte[] DiscardBuffer_1 = new byte[bytes_1];
                        serial1.Read(DiscardBuffer_1, 0, bytes_1);
                    }
                    bool ReceEquipmentisTrue;
                    ReceEquipmentisTrue = ReceModbusDataIsTrue(Recbuffer, 7);
                    if ((ReceEquipmentisTrue == true) && (Recbuffer[1] == 0x0F)&& (Recbuffer[4] == 0x00))
                    {
                       
                    }
                    else
                    {
                        //MessageBox.Show("打开激光通讯出错");
                    }
                }
                else
                {
                    MessageBox.Show("串口没打开！");
                }
            }
            else
            {
               
                
                if (isOpen == false)
                {
                    button3.Text = "打开激光";isOpen = false;
                    
                    byte[] MakeLaserClose = new byte[] { 0x01, 0x0f, 0x00, 0xff, 0x31, 0xDB };
                    if (serial1.IsOpen)
                    {
                        MakeLaserClose[0] = BitConverter.GetBytes(int.Parse(textBox1.Text))[0];
                        byte[] NeedToMakeCRCdata = new byte[4];
                        NeedToMakeCRCdata = MakeLaserClose.Skip(0).Take(4).ToArray();
                        byte[] CRCresult = new byte[2];
                        CRCresult = CRC16.CRCCalc(NeedToMakeCRCdata);
                        MakeLaserClose[4] = CRCresult[0];
                        MakeLaserClose[5] = CRCresult[1];
                        serial1_send_data(MakeLaserClose);
                        System.Threading.Thread.Sleep(500);
                        int bytes = serial1.BytesToRead;

                        byte[] Recbuffer = new byte[7] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 声明一个临时数组存储当前来的串口数据
                        if (bytes == 7)
                        {
                            try { serial1.Read(Recbuffer, 0, 7); } catch { };
                        }
                        else
                        {
                            int bytes_1 = serial1.BytesToRead;
                            byte[] DiscardBuffer_1 = new byte[bytes_1];
                            serial1.Read(DiscardBuffer_1, 0, bytes_1);
                        }
                        bool ReceEquipmentisTrue;
                        ReceEquipmentisTrue = ReceModbusDataIsTrue(Recbuffer, 7);
                        if ((ReceEquipmentisTrue == true) && (Recbuffer[1] == 0x0F) && (Recbuffer[4] == 0x00))
                        {
                             
                        }
                        else
                        {
                            //MessageBox.Show("关闭激光通讯出错");
                        }
                    }
                    else
                    {
                        MessageBox.Show("串口没打开！");
                    }
                }
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            byte[] AskEquipmentNumber = new byte[] { 0xFA, 0x25, 0x02, 0x00, 0x00, 0x01, 0x99, 0xFE };
            if (serial1.IsOpen)
            {
                serial1_send_data(AskEquipmentNumber);
                System.Threading.Thread.Sleep(500);
                int bytes = serial1.BytesToRead;
                byte[] Recbuffer = new byte[6] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 声明一个临时数组存储当前来的串口数据
                if (bytes == 6)
                {
                    try { serial1.Read(Recbuffer, 0, 6); } catch { };
                }
                else
                {
                    int bytes_1 = serial1.BytesToRead;
                    byte[] DiscardBuffer_1 = new byte[bytes_1];
                    serial1.Read(DiscardBuffer_1, 0, bytes_1);
                }
                bool ReceEquipmentisTrue;
                ReceEquipmentisTrue = ReceModbusDataIsTrue(Recbuffer, 6);
                if ((ReceEquipmentisTrue == true) && (Recbuffer[1] == 0x25))
                {
                    textBox1.Text = string.Format("{0:D3}", Recbuffer[3]);

                }
                else if (Recbuffer[3] == 0xff)
                {
                    MessageBox.Show("设备号错误");
                }
                else
                {
                    MessageBox.Show("接收帧错误");
                }
            }
            else
            {
                MessageBox.Show("串口没打开！");
            }
        }
        public static class CRC16
        {
            /// <summary>
            /// CRC校验，参数data为byte数组
            /// </summary>
            /// <param name="data">校验数据，字节数组</param>
            /// <returns>字节0是高8位，字节1是低8位</returns>
            public static byte[] CRCCalc(byte[] data)
            {
                //crc计算赋初始值
                int crc = 0xffff;
                for (int i = 0; i < data.Length; i++)
                {
                    crc = crc ^ data[i];
                    for (int j = 0; j < 8; j++)
                    {
                        int temp;
                        temp = crc & 1;
                        crc = crc >> 1;
                        crc = crc & 0x7fff;
                        if (temp == 1)
                        {
                            crc = crc ^ 0xa001;
                        }
                        crc = crc & 0xffff;
                    }
                }
                //CRC寄存器的高低位进行互换
                byte[] crc16 = new byte[2];
                //CRC寄存器的高8位变成低8位，
                crc16[1] = (byte)((crc >> 8) & 0xff);
                //CRC寄存器的低8位变成高8位
                crc16[0] = (byte)(crc & 0xff);
                return crc16;
            }

            /// <summary>
            /// CRC校验，参数为空格或逗号间隔的字符串
            /// </summary>
            /// <param name="data">校验数据，逗号或空格间隔的16进制字符串(带有0x或0X也可以),逗号与空格不能混用</param>
            /// <returns>字节0是高8位，字节1是低8位</returns>
            public static byte[] CRCCalc(string data)
            {
                //分隔符是空格还是逗号进行分类，并去除输入字符串中的多余空格
                IEnumerable<string> datac = data.Contains(",") ? data.Replace(" ", "").Replace("0x", "").Replace("0X", "").Trim().Split(',') : data.Replace("0x", "").Replace("0X", "").Split(' ').ToList().Where(u => u != "");
                List<byte> bytedata = new List<byte>();
                foreach (string str in datac)
                {
                    bytedata.Add(byte.Parse(str, System.Globalization.NumberStyles.AllowHexSpecifier));
                }
                byte[] crcbuf = bytedata.ToArray();
                //crc计算赋初始值
                return CRCCalc(crcbuf);
            }

            /// <summary>
            ///  CRC校验，截取data中的一段进行CRC16校验
            /// </summary>
            /// <param name="data">校验数据，字节数组</param>
            /// <param name="offset">从头开始偏移几个byte</param>
            /// <param name="length">偏移后取几个字节byte</param>
            /// <returns>字节0是高8位，字节1是低8位</returns>
            public static byte[] CRCCalc(byte[] data, int offset, int length)
            {
                byte[] Tdata = data.Skip(offset).Take(length).ToArray();
                return CRCCalc(Tdata);
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            byte[] SetEquipmentNumber = new byte[] { 0x01, 0x06, 0x0B, 0x00, 0x00, 0x02, 0x0A, 0x2F };
            if (serial1.IsOpen)
            {
                SetEquipmentNumber[0] = BitConverter.GetBytes(int.Parse(textBox1.Text))[0];
                SetEquipmentNumber[5] = BitConverter.GetBytes(int.Parse(textBox3.Text))[0];
                byte[] NeedToMakeCRCdata = new byte[6];
                NeedToMakeCRCdata = SetEquipmentNumber.Skip(0).Take(6).ToArray();
                byte[] CRCresult = new byte[2];
                CRCresult = CRC16.CRCCalc(NeedToMakeCRCdata);
                SetEquipmentNumber[6] = CRCresult[0];
                SetEquipmentNumber[7] = CRCresult[1];
                serial1_send_data(SetEquipmentNumber);
                System.Threading.Thread.Sleep(500);
                int bytes = serial1.BytesToRead;

                byte[] Recbuffer = new byte[6] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 声明一个临时数组存储当前来的串口数据
                if (bytes == 6)
                {
                    try { serial1.Read(Recbuffer, 0, 6); } catch { };
                }
                else
                {
                    int bytes_1 = serial1.BytesToRead;
                    byte[] DiscardBuffer_1 = new byte[bytes_1];
                    serial1.Read(DiscardBuffer_1, 0, bytes_1);
                }
                bool ReceEquipmentisTrue;
                ReceEquipmentisTrue = ReceModbusDataIsTrue(Recbuffer, 6);
                if ((ReceEquipmentisTrue == true) && (Recbuffer[1] == 0x25) && (Recbuffer[4] != 0xFF))
                {
                    MessageBox.Show("新设备地址生效，请重新读取！");
                }
                else
                {
                    MessageBox.Show("设置设备地址失败");
                }
            }
            else
            {
                MessageBox.Show("串口没打开！");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            byte[] AskEquipmentTemperature = new byte[] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A };
            if (serial1.IsOpen)
            {
                AskEquipmentTemperature[0] = BitConverter.GetBytes(int.Parse(textBox1.Text))[0];
                byte[] NeedToMakeCRCdata = new byte[6];
                NeedToMakeCRCdata = AskEquipmentTemperature.Skip(0).Take(6).ToArray();
                byte[] CRCresult = new byte[2];
                CRCresult = CRC16.CRCCalc(NeedToMakeCRCdata);
                AskEquipmentTemperature[6] = CRCresult[0];
                AskEquipmentTemperature[7] = CRCresult[1];
                serial1_send_data(AskEquipmentTemperature);
                System.Threading.Thread.Sleep(500);
                int bytes = serial1.BytesToRead;

                byte[] Recbuffer = new byte[7] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 声明一个临时数组存储当前来的串口数据
                if (bytes == 7)
                {
                    try { serial1.Read(Recbuffer, 0, 7); } catch { };
                }
                else
                {
                    int bytes_1 = serial1.BytesToRead;
                    byte[] DiscardBuffer_1 = new byte[bytes_1];
                    serial1.Read(DiscardBuffer_1, 0, bytes_1);
                }
                bool ReceEquipmentisTrue;
                ReceEquipmentisTrue = ReceModbusDataIsTrue(Recbuffer, 7);
                if ((ReceEquipmentisTrue == true) && (Recbuffer[1] == 0x03))
                {
                    textBox2.Text = string.Format("{0:D4}", Recbuffer[3] * 256 + Recbuffer[4]);
                }
                else
                {
                    MessageBox.Show("温度没读到！可能没有读设备地址！");
                }
            }
            else
            {
                MessageBox.Show("串口没打开！");
            }
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        { 
            serial1.Close();//退出时释放串口
            Environment.Exit(0);
            Process.GetCurrentProcess().Kill();
        }


        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {

        }

        private void label4_Click(object sender, EventArgs e)
        {
            pictureBox2.Hide();
        }

        private void pictureBox2_Click(object sender, EventArgs e)
        {

        }

        private void pictureBox2_Click_1(object sender, EventArgs e)
        {
            
        }
    }
}
